0b463c
@@ -16,11 +16,15 @@
 
 package org.springframework.util;
 
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Package-protected helper class for {@link AntPathMatcher}.
- * Tests whether or not a string matches against a pattern.
+ * Tests whether or not a string matches against a pattern using a regular expression.
  *
  * <p>The pattern may contain special characters: '*' means zero or more characters;
  * '?' means one and only one character; '{' and '}' indicate a URI template pattern.
@@ -30,189 +34,66 @@
import java.util.Map;
  */
 class AntPatchStringMatcher {
 
-	private final char[] patArr;
+	private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{([^/]+?)\\}");
 
-	private final char[] strArr;
+	private final Pattern pattern;
 
-	private int patIdxStart = 0;
+	private String str;
 
-	private int patIdxEnd;
-
-	private int strIdxStart = 0;
-
-	private int strIdxEnd;
-
-	private char ch;
+	private final List<String> variableNames = new LinkedList<String>();
 
 	private final Map<String, String> uriTemplateVariables;
 
-
-	/**
-	 * Construct a new instance of the <code>AntPatchStringMatcher</code>.
-	 */
-	public AntPatchStringMatcher(String pattern, String str, Map<String, String> uriTemplateVariables) {
-		this.patArr = pattern.toCharArray();
-		this.strArr = str.toCharArray();
-		this.patIdxEnd = this.patArr.length - 1;
-		this.strIdxEnd = this.strArr.length - 1;
+	/** Construct a new instance of the <code>AntPatchStringMatcher</code>. */
+	AntPatchStringMatcher(String pattern, String str, Map<String, String> uriTemplateVariables) {
+		this.str = str;
 		this.uriTemplateVariables = uriTemplateVariables;
+		this.pattern = createPattern(pattern);
 	}
 
-
-	/**
-	 * Main entry point.
-	 * @return <code>true</code> if the string matches against the pattern, or <code>false</code> otherwise.
-	 */
-	public boolean matchStrings() {
-		if (shortcutPossible()) {
-			return doShortcut();
-		}
-		if (patternContainsOnlyStar()) {
-			return true;
-		}
-		if (patternContainsOneTemplateVariable()) {
-			addTemplateVariable(0, patIdxEnd, 0, strIdxEnd);
-			return true;
-		}
-		if (!matchBeforeFirstStarOrCurly()) {
-			return false;
-		}
-		if (allCharsUsed()) {
-			return onlyStarsLeft();
-		}
-		if (!matchAfterLastStarOrCurly()) {
-			return false;
-		}
-		if (allCharsUsed()) {
-			return onlyStarsLeft();
-		}
-		// process pattern between stars. padIdxStart and patIdxEnd point
-		// always to a '*'.
-		while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
-			int patIdxTmp;
-			if (patArr[patIdxStart] == '{') {
-				patIdxTmp = findClosingCurly();
-				addTemplateVariable(patIdxStart, patIdxTmp, strIdxStart, strIdxEnd);
-				patIdxStart = patIdxTmp + 1;
-				strIdxStart = strIdxEnd + 1;
-				continue;
-			}
-			patIdxTmp = findNextStarOrCurly();
-			if (consecutiveStars(patIdxTmp)) {
-				continue;
-			}
-			// Find the pattern between padIdxStart & padIdxTmp in str between
-			// strIdxStart & strIdxEnd
-			int patLength = (patIdxTmp - patIdxStart - 1);
-			int strLength = (strIdxEnd - strIdxStart + 1);
-			int foundIdx = -1;
-			strLoop:
-			for (int i = 0; i <= strLength - patLength; i++) {
-				for (int j = 0; j < patLength; j++) {
-					ch = patArr[patIdxStart + j + 1];
-					if (ch != '?') {
-						if (ch != strArr[strIdxStart + i + j]) {
-							continue strLoop;
-						}
-					}
-				}
-
-				foundIdx = strIdxStart + i;
-				break;
-			}
-
-			if (foundIdx == -1) {
-				return false;
-			}
-
-			patIdxStart = patIdxTmp;
-			strIdxStart = foundIdx + patLength;
-		}
-
-		return onlyStarsLeft();
-	}
-
-	private void addTemplateVariable(int curlyIdxStart, int curlyIdxEnd, int valIdxStart, int valIdxEnd) {
-		if (uriTemplateVariables != null) {
-			String varName = new String(patArr, curlyIdxStart + 1, curlyIdxEnd - curlyIdxStart - 1);
-			String varValue = new String(strArr, valIdxStart, valIdxEnd - valIdxStart + 1);
-			uriTemplateVariables.put(varName, varValue);
-		}
-	}
-
-	private boolean consecutiveStars(int patIdxTmp) {
-		if (patIdxTmp == patIdxStart + 1 && patArr[patIdxStart] == '*' && patArr[patIdxTmp] == '*') {
-			// Two stars next to each other, skip the first one.
-			patIdxStart++;
-			return true;
-		}
-		return false;
-	}
-
-	private int findNextStarOrCurly() {
-		for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
-			if (patArr[i] == '*' || patArr[i] == '{') {
-				return i;
+	private Pattern createPattern(String pattern) {
+		StringBuilder patternBuilder = new StringBuilder();
+		Matcher m = GLOB_PATTERN.matcher(pattern);
+		int end = 0;
+		while (m.find()) {
+			patternBuilder.append(quote(pattern, end, m.start()));
+			String match = m.group();
+			if ("?".equals(match)) {
+				patternBuilder.append('.');
 			}
-		}
-		return -1;
-	}
-
-	private int findClosingCurly() {
-		for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
-			if (patArr[i] == '}') {
-				return i;
+			else if ("*".equals(match)) {
+				patternBuilder.append(".*");
 			}
-		}
-		return -1;
-	}
-
-	private boolean onlyStarsLeft() {
-		for (int i = patIdxStart; i <= patIdxEnd; i++) {
-			if (patArr[i] != '*') {
-				return false;
+			else if (match.startsWith("{") && match.endsWith("}")) {
+				patternBuilder.append("(.*)");
+				variableNames.add(m.group(1));
 			}
+			end = m.end();
 		}
-		return true;
-	}
-
-	private boolean allCharsUsed() {
-		return strIdxStart > strIdxEnd;
+		patternBuilder.append(quote(pattern, end, pattern.length()));
+		return  Pattern.compile(patternBuilder.toString());
 	}
 
-	private boolean shortcutPossible() {
-		for (char ch : patArr) {
-			if (ch == '*' || ch == '{' || ch == '}') {
-				return false;
-			}
+	private String quote(String s, int start, int end) {
+		if (start == end) {
+			return "";
 		}
-		return true;
+		return Pattern.quote(s.substring(start, end));
 	}
 
-	private boolean doShortcut() {
-		if (patIdxEnd != strIdxEnd) {
-			return false; // Pattern and string do not have the same size
-		}
-		for (int i = 0; i <= patIdxEnd; i++) {
-			ch = patArr[i];
-			if (ch != '?') {
-				if (ch != strArr[i]) {
-					return false;// Character mismatch
-				}
-			}
-		}
-		return true; // String matches against pattern
-	}
-
-	private boolean patternContainsOnlyStar() {
-		return (patIdxEnd == 0 && patArr[0] == '*');
-	}
-
-	private boolean patternContainsOneTemplateVariable() {
-		if ((patIdxEnd >= 2 && patArr[0] == '{' && patArr[patIdxEnd] == '}')) {
-			for (int i = 1; i < patIdxEnd; i++) {
-				if (patArr[i] == '}') {
-					return false;
+	/**
+	 * Main entry point.
+	 *
+	 * @return <code>true</code> if the string matches against the pattern, or <code>false</code> otherwise.
+	 */
+	public boolean matchStrings() {
+		Matcher matcher = pattern.matcher(str);
+		if (matcher.matches()) {
+			if (uriTemplateVariables != null) {
+				for (int i = 1; i <= matcher.groupCount(); i++) {
+					String name = this.variableNames.get(i - 1);
+					String value = matcher.group(i);
+					uriTemplateVariables.put(name, value);
 				}
 			}
 			return true;
@@ -222,30 +103,4 @@
class AntPatchStringMatcher {
 		}
 	}
 
-	private boolean matchBeforeFirstStarOrCurly() {
-		while ((ch = patArr[patIdxStart]) != '*' && ch != '{' && strIdxStart <= strIdxEnd) {
-			if (ch != '?') {
-				if (ch != strArr[strIdxStart]) {
-					return false;
-				}
-			}
-			patIdxStart++;
-			strIdxStart++;
-		}
-		return true;
-	}
-
-	private boolean matchAfterLastStarOrCurly() {
-		while ((ch = patArr[patIdxEnd]) != '*' && ch != '}' && strIdxStart <= strIdxEnd) {
-			if (ch != '?') {
-				if (ch != strArr[strIdxEnd]) {
-					return false;
-				}
-			}
-			patIdxEnd--;
-			strIdxEnd--;
-		}
-		return true;
-	}
-
 }
